define(function(require, exports, module) {

  // var Backbone = require('backbone');
  var $ = require('jquery');
  var _ = require('underscore');
  // var jsonview = require('jsonview');
  var tmpl = require('text!../tmpl.html');

  var graphUtil = require("hy5b/graph/index")
  var mathUtil = require('hy5b/math/index') 

  var addReduce = require('hy5b/animation/add-reduce')

  var THREE = require('three');

  window.THREE = THREE

  function main() {
    var $app = $('<div id="app">');
    $('#main').html($app);

    $app.append(tmpl);

    require([
      '/d/threejs-0.106.2/examples/js/loaders/VTKLoader'
    ], function() {
      app($app)
    })
    
  }

  function app($app) {
    const w = 1280;
    const h = 720;
    const aspect = w / h;

    let params = {
      lightIntensity: [0.6, 0.1],
      cameraRZ: 150,
      cameraFrustumSize: 300,
      cameraPX: 200,
      cameraPY: 200,
      cameraPZ: 200,

      mapPX: 100,
      mapPY: 100,
      mapPZ: 0,
      mapSX: 1,
      mapSY: 1,
      mapSZ: 1,
      mapRX: [0, Math.PI / 8],
      mapRY: [0, Math.PI / 8],
      mapRZ: [0, Math.PI / 8],
      textureRepeat: 1,
      rStep: [0.05, 0.01],
    };

    manualControlHelp();

    var camera, scene, renderer, light, drLight;
    var clock = new THREE.Clock()
    var oStore = {};

    initRenderer();
    $('.webgl').append(renderer.domElement)
    initScene();
    initCamera();
    initLight();

    // your code

    var geometry = new THREE.Geometry()

    geometry.vertices.push(
      new THREE.Vector3(-10, 10, 0),
      new THREE.Vector3(-10, -10, 0),
      new THREE.Vector3(10, -10, 0)
    )

    var colors = [
      new THREE.Color(0xff0000),
      new THREE.Color(0x00ff00),
      new THREE.Color(0x0000ff)
    ]

    var textureLoader = new THREE.TextureLoader();

    var vtkLoader = new THREE.VTKLoader()

    var texture = textureLoader.load('/assets/img/pic.jpg')
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping

    var material = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, wireframe: false })
    var wireframeMeterial = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true })
    var pointsMaterial = new THREE.PointsMaterial({ color: 0xec494e, size: 1.0 })

    var geometry = new THREE.PlaneGeometry(60, 20)

    var len = geometry.faces.length || 1;

    for (var i = 0; i < len; i += 2) {
      let face = geometry.faces[i];
      if (!face) {
        face = new THREE.Face3(0, 1, 2);
        geometry.faces.push(face);
      } else {
        face.vertexColors.push(...colors)
        geometry.faces[i+1].vertexColors.push(colors[1], colors[0], colors[2])
      }
    }

    // var face = new THREE.Face3(2, 1, 0)
    // face.vertexColors.push(...colors.reverse())
    // geometry.faces.push(face);

    var mesh = new THREE.Mesh(geometry, material)
    // mesh.position.set(10, 10, 0)

    var group = new THREE.Group()

    var rPoint = [-10, 10, 10]

    group.position.set(...rPoint)

    // mesh.position.set(-rPoint[0], -rPoint[1]-rPoint[2])

    scene.add(mesh)

    mesh.rotation.z = Math.PI / 2
    mesh.position.x = 20

    // scene.add(group)

    vtkLoader.load('/d/threejs-0.106.2/examples/models/vtk/bunny.vtk', function(bunnyGeometry) {
      var scale = 1000;

      var bunnyMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.FrontSide })
      bunnyGeometry.computeVertexNormals();

      // var mesh = new THREE.Mesh(bunnyGeometry, wireframeMeterial)

      //粒子系统
      var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 20, 20)
      var planeBufferGeometry = new THREE.PlaneBufferGeometry(1000, 1000, 20, 20)
      var particles = createPaticals(planeBufferGeometry, 0xec494e)
      scene.add(particles)

      return
      
      var mesh = createPaticals(bunnyGeometry, null, 1.0)

      mesh.scale.set(scale, scale, scale)
      mesh.rotation.x = - Math.PI / 2
      mesh.rotation.z = Math.PI
      mesh.rotation.y = Math.PI / 4

      var vtk = new THREE.Object3D()
      vtk.add(mesh)

      // vtk.position.x = params.mapPX
      // vtk.position.y = params.mapPY
      // vtk.position.z = params.mapPZ

      // vtk.rotation.x = params.mapRX
      // vtk.rotation.y = params.mapRY
      // vtk.rotation.z = params.mapRZ
      // scene.add(vtk)

      var boxHelper = new THREE.BoxHelper(mesh)
      // vtk.add(boxHelper)

      var newVtk = new THREE.Object3D();
      newVtk.add(vtk);
      scene.add(newVtk);

      // newVtk.position.z = 17
      vtk.position.z = -34

      let axesHelper = new THREE.AxesHelper(20);
      vtk.add(axesHelper);

      oStore.vtk = vtk;

      var positionBufferAttribute = bunnyGeometry.getAttribute('position')
      bunnyGeometry.addAttribute('initialPosition', positionBufferAttribute.clone());

      var { count, array, itemSize } = positionBufferAttribute

      for (var i = 0; i < count; i++) {
        positionBufferAttribute.setX(i, positionBufferAttribute.getX(i) + 50 / scale * Math.random())
        positionBufferAttribute.setY(i, 0)
        positionBufferAttribute.setZ(i, positionBufferAttribute.getZ(i) + 50 / scale * Math.random())
      }

      oStore.mesh = mesh
      oStore.scale = scale
      oStore.count = 0
      oStore.speed = 100 / scale

      step()
    })


    function createPaticals(geometry, color, size) {
      var pointsMaterial = new THREE.PointsMaterial({ color: color || 0xec494e, size: size || 3.0 })
      var mesh = new THREE.Points(geometry, pointsMaterial)
      return mesh;
    }


    //your code end


    step();

    function initRenderer() {
      if (!renderer) {
        renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        renderer.setSize(w, h);
        renderer.setClearColor(0x000000, 1.0);
        renderer.setPixelRatio(window.devicePixelRatio)

        // renderer.shadowMap.enabled = true;
        // renderer.shadowMapType = THREE.PCFSoftShadowMap;
      } else {
        renderer.setSize(w, h)
      }
      return renderer;
    }

    function initScene() {
      scene = new THREE.Scene()

      let axesHelper = new THREE.AxesHelper(500);
      scene.add(axesHelper);

      var helper = new THREE.GridHelper(1000, 100);
      helper.rotation.x = Math.PI / 2; //默认不是x,y平面
      helper.material.opacity = 0.25;
      helper.material.transparent = true;
      scene.add(helper);

      return scene;
    }

    function initCamera() {
      const frustumSize = params.cameraFrustumSize
      const near = 0.01;
      const far = mathUtil.vector3Length(params.cameraPX, params.cameraPY, params.cameraPZ) * 2;
      if (!camera) {
        camera = new THREE.OrthographicCamera(
        frustumSize * aspect / -2,
        frustumSize * aspect / 2,
        frustumSize / 2,
        frustumSize / -2, near, far)
      } else {
        camera.left = frustumSize * aspect / -2
        camera.right = frustumSize * aspect / 2
        camera.top = frustumSize / 2
        camera.bottom = frustumSize / -2
        camera.near = near
        camera.far = far
        camera.updateProjectionMatrix()
      }
      console.log('camera near:', near, 'far:', far, 'x*y:', frustumSize * aspect, 'x', frustumSize)
      camera.position.x = params.cameraPX
      camera.position.y = params.cameraPY
      camera.position.z = params.cameraPZ
      camera.lookAt(0,0,0)
      camera.rotation.z = params.cameraRZ * Math.PI / 180 //要在lookAt后
      return camera;
    }


    function initLight() {

      if (!light) {
        light = new THREE.AmbientLight(0xffffff);
        light.position.set(100, 100, 100)
        // scene.add(light)
      }
      
      if (!drLight) {
        drLight = new THREE.DirectionalLight(0xffffff, params.lightIntensity);
        // drLight.position.set(100, 100, 100).normalize() // normalize方法？
        drLight.position.set(100, 100, 100)

        if (1) {
          scene.add(drLight)
        } {
          // 课程22里面是这样的,不知道是为什么?说是模拟光是从相机的位置发出
          camera.add(drLight);
          camera.add(drLight.target);
          scene.add(camera);
        }
        
      } else {
        drLight.intensity = params.lightIntensity
      }
      
      
    }

    var timer;

    function step() {
      if (timer) {
        cancelAnimationFrame(timer)
      }
      timer = requestAnimationFrame(step);

      initCamera();

      initLight()

      group.rotation.x += params.rStep

      var vtk = oStore.vtk

      if (vtk) {
        vtk.position.x = params.mapPX
        vtk.position.y = params.mapPY
        vtk.position.z = params.mapPZ

        vtk.rotation.x = params.mapRX
        vtk.rotation.y = params.mapRY
        vtk.rotation.z += params.rStep
      }

      var delta = clock.getDelta()

      // var mesh = oStore.mesh
      // if (mesh) {
      //   var bufferAttribute = mesh.geometry.getAttribute('position')
      //   var initialBufferAttribute = mesh.geometry.getAttribute('initialPosition')
      //   var { count, array, itemSize } = bufferAttribute

      //   for (var i = 0; i < count; i++) {
      //     var px = bufferAttribute.getX(i)
      //     var py = bufferAttribute.getY(i)
      //     var pz = bufferAttribute.getZ(i)

      //     var ix = initialBufferAttribute.getX(i)
      //     var iy = initialBufferAttribute.getY(i)
      //     var iz = initialBufferAttribute.getZ(i)

      //     var dx = Math.abs(ix - px);
      //     var dy = Math.abs(iy - py);
      //     var dz = Math.abs(iz - pz);

      //     if (mathUtil.vector3Length(dx, dy, dz) > 1 / oStore.scale) {
      //       bufferAttribute.setXYZ(
      //         i,
      //         px + (ix - px) / dx * (0.85 - Math.random()) * delta * oStore.speed,
      //         py + (iy - py) / dy * (1 + Math.random()) * delta * oStore.speed,
      //         pz + (iz - pz) / dz * (0.85 - Math.random()) * delta * oStore.speed
      //       )
      //     }
      //   }

      //   bufferAttribute.needsUpdate = true
      // }


      texture.repeat.x = texture.repeat.y = params.textureRepeat;

      render()
    }


    function render() {
      renderer.render(scene, camera);
    }

    function manualControlHelp() {
      _.each(params, function(v, param) {
        let val = v;
        let delta;
        if (val.length > 0) {
          delta = val[1]
          val = val[0]
          params[param] = val
        }
        $app.append(
          addReduce({
            set: (function(param) {
              return function(value) {
                params[param] = value;
                step()
              }
            }(param)),
            key: param,
            val: val,
            delta: delta
          })
        )

        $app.append('<br/>')
      })
    }
  }

  return main;
})
